//: [Previous](@previous)
//:## 访问控制(Access control)
/*
 在访问权限控制这块, Swift提供了5个不同的访问级别(以下是从高到低排列, 实体是指被访问级别修饰了的内容)(Swift的访问权限是以文件,以模块为单位,其他编辑语言有些是以类型为单位)
 1. open: 允许在定义实体的 模块 / 其他模块 中访问, 允许其他模块进行 继承 / 重写 (opoen只能用在类 / 类的成员上,因为只有类可以重写呀)(模块:Products里面的内容.比如各个动态库,有截图在resource)
 2. public: 允许定义实体的 模块 / 其他模块 中访问, 不允许其他模块进行继承和重写
 3. internal: (中文意思:内部)只允许在定义实体的模块中访问, 不允许在其他模块中访问
 4. fileprivate: 只运行在定义实体的源文件中访问(就是只能在当前这个定义的当前这一个文件访问,什么导入之类的都用不了)
 5. private: 只允许在定义实体的封闭声明中访问(比如在一个方法内定义了一个,那就只能在这个方法内使用,出了方法外都用不了了)
 
 绝大多实体部分默都是internal级别
 直接在全局作用域下定义的private等价于fileprivate
 子类重写的成员的访问级别必须 >= 父类成员的访问权限
 */
//: ## 访问级别的使用准则
/*
 一个实体 不可以被 更低访问级别的实体定义, 比如:
 
1. 变量/常量类型 >= 变量/常量
 internal class classA1{}
 fileprivate var p1: classA1
 假设类A1是被internal定义的, p1是被A1定义的变量 是fileprivate的访问级别, internal>fileprivate, 这个关系就正常.
 但是假如反之: fileprivate A1, internal p1, fileprivate是只有当前文件可以访问, 但是internal是模块中的其他文件都可以访问, 就会出现在别的文件可以调用到p1, 但是这个p1是classA1类型的变量, 这个文件却访问不到classA1类型, 就乱了
 
 2. 参数类型 / 返回值类型 >= 函数
 internal func test(_ v1: Int) -> Double{} 在文件1定义这个函数, 在文件2也可以使用, 但是使用的时候是不是必须要可以传入参数和拿到返回值啊, 这个时候是不是这2个内容一定要有访问权限, 一个函数的参数和返回值一定要别它自身的权限大, 这样子才可以保证在函数被调用的时候这2个内容肯定可以被访问
 
 3. 父类 >= 子类
    比如一个类继承了父类, 在一个地方可以访问到这个子类, 那么就一定也要可以访问到父类啊, 因为子类继承自父类, 所以必须要在子类里面能使用到父类的东西,
 4. 父协议 >= 子协议
    同上同理理解
 5. 原类型 >= typealias
   class ta {}
   fileprivate typealias myts = ta 左边要使用到右边的东西, 肯定右边的东西权限比他更大更全
 6. 原始值类型 / 关联值类型 >= 枚举
     enum myen {
         case a(String)
         case b(Int)
     } 原始值和关联值是被使用方, 相当于右边, 所以同上同理更大
   
 */
//: ## 元祖类型
internal struct Dog {}
fileprivate class Person {}
/*
 元祖类型的访问级别是取所有成员类型最低的那个
 (Dog, Person) : 这是一个元祖, 2个成员中取访问级别最低的那个, 所以就是fileprivate权限
 */
fileprivate var data1: (Dog, Person)//右边元祖的级别是fileprivate, 所以左边必选比右边更小或等于
private var data2: (Dog, Person)
//internal var data3: (Dog, Person)//internal > fileprivate, 所以就报错了
//:## 泛型类型
public class Person1<T1, T2> {}
/*
 泛型类型的访问级别是 类型的访问级别 以及 所有泛型类型参数的访问级别 中最低的那个
 Person1<Dog, Person> 的访问级别是public / internal / fileprivate, 因为最低是Person的fileprivate
 */
fileprivate var p = Person1<Dog, Person>()
private var p1 = Person1<Dog, Person>()
//:## 成员 / 嵌套类型
/*
 类型的访问级别会影响 成员(属性/方法/初始化器/下标) 和 嵌套类型 的默认访问级别
 - 一般情况下,类型为private或fileprivate的,那么成员/嵌套类型默认也是private或fileprivate
 - 一般情况下,类型为internal或public,那么成员/嵌套类型默认都是internal
 
 绝大多实体类默认都是internal级别
 */
public class PublicClass {
    var p1 = 0 //internal
    public var p2 = 0 //public ,虽然默认会是internal,但是这里已经特意标明了public,所以这个成员的访问级别还是会是public
    internal var p3 = 0 //internal
    fileprivate func f1() {} //fileprivate
    private func f2() {} //private
}
fileprivate class FileprivateClass {
    func f1() {} //fileprivate
    private func f2() {} //private
}
//:## getter/setter (读和写)
/*
 getter和setter 默认自动接收他们所属环境的访问级别
 可以给setter单独设置一个比getter更低的访问级别, 用以限制写的权限.(但是getter不能比setter低,其实这种写法就是专门用来针对setter)
 */
class gsClass {
    private(set) var age = 10 //private(set): 单独限制了set的权限是private
    
    fileprivate var weight: Int {//计算属性
        set{}
        get{10}
    }
    
    public subscript(index: Int) -> Int{ //下标
        set{}
        get{index}
    }
}
var gs1 = gsClass()
//gs1.age = 20//这里就好报错,因为写的权限被限制成了private
print(gs1.age)

/*
 也可以这样子直接在初始化的时候限制了set, 这样子写的意思是:
 gs2的访问级别是public, 但是set的访问级别单独调成set, 就可以达到效果:这个属性以后所有文件都能使用它,但是只有当前文件可以设置它的值
 */
fileprivate(set) public var gs2 = 10
//:## 初始化器
/*
 1. 如果一个 public类 想在另一个模块调用编译生成的默认无参初始化器, 必须显式提供public的无参初始化器
 因为public类的默认初始化器是internal级别, internal是不能在别的模块使用
 public class ps {
     public init() {}
 }
 2. required初始化器必须跟它所属的类拥有相同的访问级别
 3. 如果结构体有private/fileprivate的存储实例属性, 那么它的初始化器也是private/fileprivate
 4. required初始化器必须 >= 它的声明的访问级别
 struct ps {
     var x = 0
     var y = 0
 }
 var pss = ps(x: 10, y: 20) 此时x和y是默认internal
 
 struct ps {
     private var x = 0
     var y = 0
 }
 var pss = ps() 假如x的访问级别改成private, 那么整个初始化器的级别都会变成private的,所以只能使用无参的初始化器了
 */
//:## 枚举类型的case
/*
 不能给enum的每个case单独设置访问级别
 每个case自动接收enum的访问级别
 假设enum是定义public, case也会是跟随是public, 不像类和结构体定义是public,里面属性会是internal, 因为枚举的case的不能单独定义
 */
//:## 协议
/*
 协议中定义的要求会自动接收协议的访问级别, 不能单独设置访问级别
 - 协议定义了public,里面的要求也会是public
 
 协议实现的访问级别必须 >= 类型的访问级别, 或者>=协议的访问级别
 - 就是说C必须大于等于A或者B其中之一即可
 fileprivate protocol Runnable {//协议的访问级别(A)
     func run()
 }
 internal class Person2 : Runnable {//类型的访问级别(B)
     fileprivate func run() {//协议实现(C)
     }
 }

 */
//:## 扩展
/*
 1. 如果有显示设置扩展的访问级别, 扩展添加的成员自动接收扩展的访问级别
 2. 如果没有显示设置的访问级别, 扩展添加的成员的默认访问级别, 跟直接在类型中定义的成员一样
 3. 可以单独给扩展添加的成员设置访问级别
 4. 不能给用于遵守协议的扩展 显示的设置扩展的访问级别
 5. 在同一个文件中的扩展, 可以写成类似分开多个部分的类型声明(可以理解成扩展其实还是在原来的作用域之内)
  - 在原本的声明中声明了一个私有成员, 可以在同一个文件的扩展中访问到它
  - 在扩展中声明一个私有成员, 可以在同一个文件的其他扩展中/原本声明中访问到它
 public class ps1 {
     private func run1() {
         run2()//这里在声明中访问了扩展中的private的run2
     }
 }
 extension ps1 {
     private func run2() {
         run1()//这里在扩展中访问了原本声明中的private的run1
     }
 }
 
 */












//: [Next](@next)
